use crate::manifest::{Manifest, AutoReplenish, ContributeDefinitions, ContributionPointDefinitions};
use std::collections::HashMap;

// ... (other functions are the same)

pub fn replenish_all(manifests: &mut HashMap<String, Manifest>) {
    let keyword_providers: HashMap<String, String> = manifests
        .values()
        .flat_map(|m| {
            m.contribution_keywords
                .iter()
                .map(move |k| (k.name.clone(), m.name.clone()))
        })
        .collect();

    let mut additions: HashMap<String, (Option<ContributeDefinitions>, Option<ContributionPointDefinitions>)> = HashMap::new();

    for contributor in manifests.values() {
        if let Some(contributes) = &contributor.contributes {
            for (keyword_name, defs) in contributes {
                if let Some(provider_name) = keyword_providers.get(keyword_name) {
                    if let Some(provider_manifest) = manifests.get(provider_name) {
                        if let Some(keyword_def) = provider_manifest.contribution_keywords.iter().find(|k| k.name == *keyword_name) {
                            if let Some(replenish_template) = &keyword_def.contribute_auto_replenish {
                                for def in defs {
                                    let (contribs, points) = generate_replenishments(replenish_template, &def.name, &contributor.name);
                                    let entry = additions.entry(provider_name.clone()).or_default();
                                    merge_replenishments(&mut entry.0, contribs);
                                    merge_replenishments(&mut entry.1, points);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    for (manifest_name, (contrib_additions, point_additions)) in additions {
        if let Some(manifest) = manifests.get_mut(&manifest_name) {
            if let Some(additions) = contrib_additions {
                merge_replenishments(&mut manifest.contributes, Some(additions));
            }
            if let Some(additions) = point_additions {
                merge_replenishments(&mut manifest.contribution_points, Some(additions));
            }
        }
    }
}

fn generate_replenishments(template: &AutoReplenish, value: &str, contributor_name: &str) -> (Option<ContributeDefinitions>, Option<ContributionPointDefinitions>) {
    let mut new_contribs = ContributeDefinitions::new();
    if let Some(template_contribs) = &template.contributes {
        for (keyword, defs) in template_contribs {
            let new_defs = defs.iter().map(|def| {
                let mut new_def = def.clone();
                new_def.name = new_def.name.replace("{{name}}", value);
                if let Some(cp) = &mut new_def.cp {
                    *cp = cp.replace("{{name}}", value);
                }
                new_def.is_replenish = true;
                new_def.replenish_by = Some(contributor_name.to_string());
                new_def
            }).collect();
            new_contribs.insert(keyword.clone(), new_defs);
        }
    }

    let new_points = None; // Placeholder

    (Some(new_contribs), new_points)
}

fn merge_replenishments<T: Clone>(target: &mut Option<HashMap<String, Vec<T>>>, source: Option<HashMap<String, Vec<T>>>) {
    if let Some(source_map) = source {
        let target_map = target.get_or_insert_with(Default::default);
        for (key, mut values) in source_map {
            target_map.entry(key).or_default().append(&mut values);
        }
    }
}
